public abstract class Bicycle {
   // A bicycle class

  //Constants for Braking; Linear Braking (JT)
  protected final int SLOW_BRAKING     = 2;
  protected final int MODERATE_BRAKING = 4;
  protected final int FAST_BRAKING     = 8;

  //Constants for Acceleration; Linear Acceleration (JT)
  protected final int SLOW_ACCEL       = 3;
  protected final int MODERATE_ACCEL   = 6;
  protected final int FAST_ACCEL       = 12;


  //Instance Vars
	private int numGears;
	private int curGear = 1;
	private int speed;      // Speed in MPH.    

	private int weight;     // Weight of bike in lbs.
	private int length;     // Length in inches from front tire to back.
	private int tireWidth;	// Width in inches of tire.

	// Constructor
  //No-Arg constructor not used in this implementation,
  //but a different Bike subclass may need it. (JT)
  Bicycle(){
    this(12,0,64,12,2);   //Defines a default Bicycle...
  }
	Bicycle(int numGears, int speed, int length, int weight, int tireWidth) {
//		this.numGears  = numGears;
//		this.speed     = speed;
//		this.length    = length;
//		this.weight    = weight;
//		this.tireWidth = tireWidth;
    //Reimplemented with the setters and getters (JT)
    setNumGears(numGears);
    setSpeed(speed);
    setLength(length);
    setWeight(weight);
    setTireWidth(tireWidth);
	}

	abstract void brake();
    
	abstract void accelerate();

	//getter for speed
	int getSpeed() {
		return speed;
	}

	//setter for speed
	void setSpeed(int val) {
		this.speed = val;
	}
	
	//getter for curGear
	int getGear() {
		return curGear;
	}
	
	//setter for curGear
	void setGear (int gear) {
		if ((gear > 0) && (gear <= numGears))
		   curGear = gear;
		else 
		   System.err.printf("Invalid gear assignment: %d (there are only %d gears)%n", gear, numGears);
	}
	
	//setter for numGears
	void setNumGears(int val) {
		this.numGears = val;
	}
	
	//getter for numGears
	int getNumGears() {
		return numGears;
	}
	
	//setter for weight
	void setWeight(int val) {
		this.weight = val;
	}
	
	//getter for weight
	int getWeight() {
		return weight;
	}
	
	//setter for length
	void setLength(int val) {
		this.length = val;
	}
	
	//getter for length
	int getLength() {
		return length;
	}
	
	//setter for tireWidth
	void setTireWidth(int val) {
		this.tireWidth = val;
	}
	
	//getter for tireWidth
	int getTireWidth() {
		return tireWidth;
	}

  @Override
  public String toString(){
    return String.format("  Number of Gears: %2d\n" +
                         "     Current Gear: %2d\n" +
                         "    Current Speed: %2d\n" +
                         "   Bicycle Length: %2d inches.\n" +
                         "   Bicycle weight: %2d lbs.\n"    +
                         "       Tire width: %2d inches.\n",
                         getNumGears(),
                         getGear(),
                         getSpeed(),
                         getLength(),
                         getWeight(),
                         getTireWidth() );
  }//toString()

}//Bicycle Class

/**
 * MountainBike Class
 *
 */
class MountainBike extends Bicycle  //subclass of superclass Bicycle
{

  //Constructor for a default MountainBike (JT)
  public MountainBike(){
    this(20,0,64,15,2);
  }
  //Constructor for a user defined MountainBike (JT)
  public MountainBike(int numGears,
                      int speed,
                      int length,
                      int weight,
                      int tireWidth){
    super(numGears, speed, length, weight, tireWidth);
  }

//IMPLEMENTATION OF ABSTRACT METHODS (JT)

  /**
   * Apply brakes on this bike.
   */
  public void brake(){
    if (getSpeed() >= MODERATE_BRAKING){
      setSpeed(getSpeed() - MODERATE_BRAKING);
    } else {
      setSpeed(0);
    }//if/else
  }//brake()

  /**
   * Accelerate this bike.
   */
	public void accelerate(){
    setSpeed(getSpeed() + MODERATE_ACCEL);
  }//accelerate()

  /**
   * Format a display string for this bike.
   * @return  The formatted display string.
   */
  @Override
  public String toString(){
    return String.format("Mountain Bike Stats:\n%s", super.toString());
  }
  
}//MountainBike Class


/**
 * RaceBike Class
 * 
 */
class RaceBike extends Bicycle  //subclass of superclass Bicycle
{

  //Constructor for a default RaceBike (JT)
  public RaceBike(){
    this(22,0,64,5,1);
  }
  //Constructor for a user defined RaceBike (JT)
  public RaceBike(int numGears,
                      int speed,
                      int length,
                      int weight,
                      int tireWidth){
    super(numGears, speed, length, weight, tireWidth);
  }

//IMPLEMENTATION OF ABSTRACT METHODS (JT)

  /**
   * Apply brakes on this bike.
   */
  public void brake(){
    if (getSpeed() >= FAST_BRAKING){
      setSpeed(getSpeed() - FAST_BRAKING);
    } else {
      setSpeed(0);
    }//if/else
  }

  /**
   * Accelerate this bike.
   */
	public void accelerate(){
    setSpeed(getSpeed() + FAST_ACCEL);
  }//accelerate()

  /**
   * Format a display string for this bike.
   * @return  The formatted display string.
   */
  @Override
  public String toString(){
    return String.format("Race Bike Stats:\n%s", super.toString());
  }

}//RaceBike class


/**
 * TandemBike Class
 * 
 */
class TandemBike extends Bicycle  //subclass of superclass Bicycle
{

  //Constructor for a default TandemBike (JT)
  public TandemBike(){
    this(12,0,96,25,1);
  }
  //Constructor for a user defined TandemBike (JT)
  public TandemBike(int numGears,
                      int speed,
                      int length,
                      int weight,
                      int tireWidth){
    super(numGears, speed, length, weight, tireWidth);
  }


//IMPLEMENTATION OF ABSTRACT METHODS (JT)

  /**
   * Apply brakes on this bike.
   */
  public void brake(){
    if (getSpeed() > 0){
      setSpeed(getSpeed() - SLOW_BRAKING);
    } else {
      setSpeed(0);
    }//if/else
  }//brake()

  /**
   * Accelerate this bike.
   */
	public void accelerate(){
    setSpeed(getSpeed() + SLOW_ACCEL);
  }//accelerate()

  /**
   * Format a display string for this bike.
   * @return  The formatted display string.
   */
  @Override
  public String toString(){
    return String.format("Tandem Bike Stats:\n%s", super.toString());
  }

}//TandemBike Class
